#pragma once
#include <iostream>
#include <pthread.h>
#include <netinet/in.h>
#include "Addr.hpp"
#include "ThreadPool.hpp"
#include "task.hpp"

class UdpServer
{
public:
    UdpServer(int port):_port(port){}
    ~UdpServer()
    {
        close(_sockfd);
        ThreadPool<task>::GetInstance()->Wait();
    }
    void Init()
    {
        _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if(_sockfd < 0)
        {
            std::cout << "socket failed, errno : " << strerror(errno) << std::endl;
            exit(-1);
        }
        struct sockaddr_in server;
        memset(&server, 0, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(_port); // 注意字节序在转换时，函数要用对，port是一个16字节的数，要用 htons 函数
        server.sin_addr.s_addr = INADDR_ANY; // 接收任意ip地址发来的请求
        int n = bind(_sockfd, (struct sockaddr*)&server, sizeof(server)); // 要手动绑定，因为服务器的端口号必须时固定的，被别人所知道的，不能是随机的
        ThreadPool<task>::GetInstance()->Start();
    }
    void Start()
    {
        char buffer[1024];
        while(1)
        {
            struct sockaddr_in tmp;
            socklen_t sz = sizeof(tmp);
            int n = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)&tmp, &sz);
            if(n > 0)
            {
                buffer[n] = 0;
                std::cout << "client[" << Addr::GetInstance()->ip_port(tmp) <<"]# " << buffer << std::endl;
                Addr::GetInstance()->Add(tmp);
                ThreadPool<task>::GetInstance()->push(task(buffer, _sockfd));
            }
            else if(n == 0)
            {
                std::cout << "退出" << std::endl;
                break;
            }
            else
            {
                std::cout << "recvfrom failed, error: " << strerror(errno) << std::endl;
                break;
            }
        }
    }
private:
    int _sockfd;
    uint16_t _port;
};